#!/bin/bash
# Filename     :        get_free_cert.sh
# Last modified:        2024-08-30 12:12
# Version      :
# Author       : jack.zang
# Email        : jack.zang@aishangwei.net
# Description  :
# 使用方法：curl -O https://gitee.com/jack_zang/public-scripts/raw/master/shell/scripts/get_free_cert.sh
#          chmod +x get_free_cert.sh && ./get_free_cert.sh <DOMAIN> <AK_KEY> <AK_SECRET>
# ******************************************************

# 设置证书名称和域名
DOMAIN=$1
AK_KEY=$2
AK_SECRET=$3

# 参数验证
if [ "$#" -ne 3 ]; then
    echo "Usage: $0 <DOMAIN> <AK_KEY> <AK_SECRET>"
    exit 1
fi

# 安装 aliyun cli
install_aliyun_cli() {
    if ! command -v aliyun &> /dev/null; then
        curl -O https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz
        tar xzvf aliyun-cli-linux-latest-amd64.tgz
        mv aliyun /usr/local/bin/
    fi
}

# 配置 aliyun cli AK 凭证
configure_aliyun_cli() {
    local config_file="$HOME/.aliyun/config.json"
    if [ ! -f "$config_file" ] || ! grep -q "aliyun-ak" "$config_file"; then
        aliyun configure set --profile aliyun-ak --mode AK --region cn-hangzhou --access-key-id $AK_KEY --access-key-secret $AK_SECRET
    fi
    echo "[INFO] aliyun cli 版本为：$(aliyun version)，AK 凭证配置成功"
}

# 安装 jq
install_jq() {
    if ! command -v jq &> /dev/null; then
        apt-get update && apt-get install jq -y
    fi
}

# 计算两个日期之间的天数
calc_day() {
    current_date=$(date +%Y-%m-%d)
    echo $((($(date -d "$1" +%s) - $(date -d "$current_date" +%s)) / 86400))
}

# 获取证书状态
get_certificate_status() {
    aliyun cas ListUserCertificateOrder --region cn-hangzhou --Keyword $DOMAIN --OrderType CERT
}

# 申请证书
apply_certificate() {
    aliyun cas CreateCertificateForPackageRequest --region cn-hangzhou --Domain $DOMAIN \
    --ProductCode 'digicert-free-1-free' --ValidateType DNS
}

# 主程序
main() {
    ## 1. 安装 aliyun cli 和 jq
    install_aliyun_cli
    configure_aliyun_cli
    install_jq

    ## 2. 获取证书状态
    CHECK_STATUS=$(get_certificate_status)
    for (( i=1; i<=3; i++ )); do
        if [[ $CHECK_STATUS == *CertificateOrderList* ]]; then
            echo "[INFO] 获取域名：$DOMAIN 的 SSL 证书状态"
            echo $CHECK_STATUS
            break
        elif [[ $i -eq 3 ]]; then
            echo "[ERROR] 已尝试 3 次获取域名：$DOMAIN 的 SSL 证书状态失败，退出..."
            exit 1
        else
            echo "[WARNING] 获取域名：$DOMAIN 的 SSL 证书状态失败，正在第 $((i + 1)) 次尝试获取..."
            CHECK_STATUS=$(get_certificate_status)
        fi
    done

    ## 3. 检查证书状态
    STATUS=$(echo $CHECK_STATUS | jq -r '.CertificateOrderList.[0].Status')
    expire_day=$(echo $CHECK_STATUS | jq -r '.CertificateOrderList.[0].EndDate')
    case "$STATUS" in
        "ISSUED")
            if [ -n "$expire_day" ]; then
                day_diff=$(calc_day $expire_day)
                if [ $day_diff -gt 3 ]; then
                    echo "[INFO] 证书已经签发，有效期还有 $day_diff ，大于 3 天，证书申请退出..."
                    exit 0
                fi
            fi
            ;;
        "CHECKING")
            echo "[INFO] 证书因为未知原因正在审核中，无需再次申请，请手工进行后续操作，退出..."
            exit 1
            ;;
    esac

    ## 4. 申请证书,并等待 30s
    echo "[INFO] 开始为域名： $DOMAIN 申请一个免费证书"
    apply_certificate
    for (( i=1; i<=3; i++ )); do
        if [ $? -eq 0 ]; then
            echo "[INFO] 已申请证书，签发中，请等待 30s..."
            sleep 30
            break
        elif [[ $i -eq 3 ]]; then
            echo "[ERROR] 已尝试 3 次申请域名：$DOMAIN 的 SSL 证书失败，退出..."
            exit 1
        else
            echo "[WARNING] 申请证书失败，正在第 $((i + 1)) 次尝试申请..."
            apply_certificate
        fi
    done

    ## 5. 检查证书是否签发成功，不成功就继续等待 多个 30s，直到签发成功
    CHECK_STATUS=$(get_certificate_status)
    STATUS=$(echo $CHECK_STATUS | jq -r '.CertificateOrderList.[0].Status')
    while [ "$STATUS" != "ISSUED" ]; do
        echo "[INFO]证书还未签发，继续等待 30s..."
        sleep 30
        CHECK_STATUS=$(get_certificate_status)
        STATUS=$(echo $CHECK_STATUS | jq -r '.CertificateOrderList.[0].Status')
    done
    echo "[INFO]$DOMAIN 证书已签发"

    ## 6. 获取证书并保存到当前目录
    CERT_ID=$(echo $CHECK_STATUS | jq -r '.CertificateOrderList.[0].CertificateId')
    CERT_KEY=$(aliyun cas GetUserCertificateDetail --region cn-hangzhou --CertId $CERT_ID --CertFilter false)
    echo $CERT_KEY | jq -r '.Cert' > "${DOMAIN}.pem"
    echo $CERT_KEY | jq -r '.Key' > "${DOMAIN}.key"
    echo "[SUCCESS] 证书已保存到当前目录：${PWD}/${DOMAIN}.pem 和 ${PWD}/${DOMAIN}.key"
}

main